//>>>exception
//>>>template

#include<iostream>
using namespace std;

class RuntimeException { };

/*
object states:
   1. uninitialized
   2. just initialized
   3. used
   4. ready to be deleted

   init: 1->2
   non-const operations: 2/3->3
   clearAll: 3->2
   ~/reclaim: 2/3->4
*/
class ArrayList {
public:
   ArrayList() {
      init();
   } 
   ArrayList(ArrayList &that) {
      init(); //: An one-hour bug. Don't forget this line!
      *this=that;
   }
   const ArrayList & operator=(const ArrayList &that) { 
      if(this==&that) {
         return *this; //same object
      }
      clearAll();
      for(int i=0; i<that._size; i++) {
         append(that.values[i]);
      }
      return *this; //>>> which to return?
   }
   ~ArrayList() {
      reclaim();
   }

   void clearAll() {
      reclaim();
      init();
   }
   int get(int index) { 
      if(index<0 || index>=_size) throw RuntimeException();
      return values[index]; 
   }
   void set(int index, int value) {
      if(index<0 || index>=_size) throw RuntimeException();
      values[index]=value;
   }

   void prepend(int v) {
      if(_size==capacity) grow();
      for(int i=_size; i>0; i--) {
         values[i]=values[i-1];
      }
      _size++;
      values[0]=v;
   }
   void append(int v) {
      if(_size==capacity) grow();
      values[_size++]=v;
   }
   int deleteHead() {
      if(isEmpty()) throw RuntimeException();
      const int res=values[0];
      for(int i=0; i<_size; i++) {
         values[i]=values[i+1];
      }
      _size--;
      return res;
   }
   int deleteTail() {
      if(isEmpty()) throw RuntimeException();
      return values[--_size];
   }

   int length() const { return size(); }
   int size() const {
      return _size;
   }
   bool isEmpty() const {
      return _size==0;
   }
   void print() const {
      cout<<"[ ";
      for(int i=0; i<_size; i++) {
         cout<<values[i]<<" ";
      }
      for(int i=_size; i<capacity; i++) {
         cout<<"x"<<" ";
      }
      cout<<"]";
   }
   void println() const { print(); cout<<endl; }

private:
   int *values;
   int _size; //>>> naming convension?
   int capacity;

   const static int INI_CAPACITY=0;
   void init() {
      capacity=INI_CAPACITY;
      values=new int[capacity];
      _size=0;
   }
   void grow() {
      //const int oldCapacity=capacity;
      capacity=capacity+capacity/2+5;
      int *temp=new int[capacity];
      for(int i=0; i<_size; i++) { temp[i]=values[i]; }
      delete values;
      values=temp;
      //cerr<<"grow from "<<oldCapacity<<" to "<<capacity<<endl;
   }
   void reclaim() { delete[] values; }
};

//[ test==========================================
void testAppend() {
   ArrayList list;
   for(int i=0; i<10; i++) {
      list.append(i);
   }
   list.print();
}
void testPrepend() {
   ArrayList list;
   for(int i=0; i<10; i++) {
      list.prepend(i);
   }
   list.print();
}
void testDeleteHead() {
   ArrayList list;
   for(int i=0; i<10; i++) {
      list.append(i);
   }
   list.print();
   for(int i=0; i<10; i++) {
      cout<<list.deleteHead()<<" "<<endl;
      list.print();
   }
}
void testDeleteTail() {
   ArrayList list;
   for(int i=0; i<10; i++) {
      list.append(i);
   }
   list.print();
   for(int i=0; i<10; i++) {
      cout<<list.deleteTail()<<" "<<endl;
      list.print();
   }
}
void testClearAll() {
   ArrayList *list=new ArrayList; 
   for(int i=0; i<10; i++) {
      list->append(i);
   }
   list->print();
   list->clearAll();
   list->print();
   for(int i=0; i<10; i++) {
      list->append(i);
   }
   list->print();
}
void testDestructor() {
   ArrayList *list=new ArrayList; //>>> parentheses?
   for(int i=0; i<10; i++) {
      list->append(i);
   }
   list->print();
   delete list;
}
void testCopyCtor() {
   ArrayList a;
   for(int i=0; i<10; i++) {
      a.append(i);
   }
   a.println();
   ArrayList b=a;
   b.println();
   a.append(99);
   a.println();
   b.println();
}
void testAssignmentEquals() {
   ArrayList a;
   for(int i=0; i<10; i++) {
      a.append(i);
   }
   a.print();
   a=a;
   ArrayList b;
   b=a;
   b.print();
   a.append(99);
   a.print();
   b.append(100);
   b.print();
}
void testSize() {
   ArrayList a;
   cout<<a.size()<<endl;
   for(int i=0; i<10; i++) {
      a.append(i);
   }
   cout<<a.size()<<endl;
   a.clearAll();
   cout<<a.size()<<endl;
}
void testRuntimeException() {
   ArrayList a;
   for(int i=0; i<10; i++) {
      a.append(i);
   }
   a.print();
   for(int i=0; i<10; i++) {
      a.deleteHead();
   }
   a.deleteHead();
}
int main() {
   //testAppend();
   //testPrepend();
   //testDeleteHead();
   //testDeleteTail();
   //testClearAll();
   //testDestructor();
   //testCopyCtor();
   //testAssignmentEquals();
   //testSize();
   //testRuntimeException();
   return 0;
}
